/*
    echo sever 回声服务器
    select函数 IO多路复用
*/

#include <stdio.h>
#include <stdlib.h>
#include <sys/select.h>
#include <sys/time.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <sys/types.h>
#include <fcntl.h>
#include <sys/socket.h>
#include <netinet/in.h>

int main()
{
    // 创建套接字
    int sever_fd = socket(AF_INET, SOCK_STREAM, 0);
    
    // 端口复用
    int reuse = 1;
    setsockopt(sever_fd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse));

    // 绑定端口
    struct sockaddr_in sever_addr;
    sever_addr.sin_family = AF_INET;
    sever_addr.sin_addr.s_addr = htonl(INADDR_ANY);
    sever_addr.sin_port = htons(8889);
    int ret = bind(sever_fd, (struct sockaddr*)&sever_addr, sizeof(sever_addr));
    if(ret == -1)
    {
        perror("select");
        exit(1);
    }
    if(listen(sever_fd, 10) == -1)
    {
        perror("listen");
        exit(1);
    }
    printf("Echo server started on port 8888\n");

    fd_set readfds;
    int max_fd = sever_fd;

    while(1)
    {
        // 每次循环先清零
        FD_ZERO(&readfds);
        FD_SET(sever_fd, &readfds);
        
        // 将已连接的客户端对应的socket对象 添加到读集合中
        // 最多select对象可以监听1024个对象
        static int client_fds[1024] = {0};
        for(int i = 0; i < 1024; i++)
        {
            if(client_fds[i] != 0)
                FD_SET(client_fds[i], &readfds);
        }
        // 调用select 函数监听
        int count = select(max_fd+1, &readfds, NULL, NULL, NULL);
        if(count == -1)
        {
            perror("select failed");
            continue;
        }
        if(FD_ISSET(sever_fd, &readfds))
        {
            int new_fd;
            if((new_fd = accept(sever_fd, NULL, NULL)) == -1)
            {
                perror("connect");
                continue;
            }
            printf("New connection, fd: %d\n", new_fd);

            // 将新的文件描述符放入数据，更新max_fd
            for(int i = 0; i < 1024; i++)
            {
                if(client_fds[i] == 0)
                {
                    client_fds[i] = new_fd;
                    if(new_fd > max_fd)
                        max_fd = new_fd;
                    break;
                }
            }
        }

        // 处理客户端数据（监听客户端的socket是否就绪）
        for(int i = 0; i < 1024; i++)
        {
            int fd = client_fds[i];
            if(fd == 0 || !FD_ISSET(fd, &readfds))
                continue;
            // 监听到了，这个就绪 处理
            // 读取数据
            char buf[1024] = {0};
            size_t size = read(fd, buf, sizeof(buf));
            if(size == 0)
            {
                // 客户端断开或出错
                close(fd);
                printf("Client disconnected, fd: %d\n", fd);
                client_fds[i] = 0;
            }
            else{
                printf("Received from fd %d: %s\n", fd, buf);
                write(fd, buf, size);  // 原样返回
            }
        }
    }
    close(sever_fd);
    return 0;
}

